#include "Thread.h"
#include "helpMacros.h"
#include SD_TL_PLATFORM_IMPL_INC( tools,Thread )

#include <boost/bind.hpp>
#include <functional>
#include <algorithm>

using namespace sd::tools::thread;



namespace sd{
namespace tools{
namespace thread{
namespace impl{

ThreadBase::ThreadBase(){}


ThreadBase::~ThreadBase(){}



void ThreadBase::kill()
{
	std::for_each( impl_.begin(),  impl_.end(), boost::bind(&ThreadImpl::kill, _1 ));
}

void ThreadBase::suspend()
{
	std::for_each( impl_.begin(),  impl_.end(), boost::bind(&ThreadImpl::suspend, _1 ));
}
void ThreadBase::resume()
{
	std::for_each( impl_.begin(),  impl_.end(), boost::bind(&ThreadImpl::resume, _1 ));
}

bool ThreadBase::isSuspended()
{
	return std::count_if( impl_.begin(),  impl_.end(), boost::bind(&ThreadImpl::isSuspended, _1 )) == impl_.size();
}

bool ThreadBase::isFinished()
{
	return std::count_if( impl_.begin(),  impl_.end(), boost::bind(&ThreadImpl::isFinished, _1 )) == impl_.size();
}

bool ThreadBase::operator==(const ThreadBase& ref)const
{
	const_iterator it1 = begin(), it2 = ref.begin();
	for(  ; it1!=end() && (*it1)->getId()==(*it2)->getId(); ++it1, ++it2 );
	return it1==end();
}

ThreadImplRef& ThreadBase::get(int index)
{
	return impl_[index];
}
const ThreadImplRef& ThreadBase::get(int index)const
{
	return impl_[index];
}

int ThreadBase::find( const ThreadImplRef& ref )const
{
	for( size_t i=0; i < impl_.size(); ++i)
		if( impl_[i]->getId() == ref->getId() )
			return i;
	return -1;
}

void ThreadBase::remove(int index)
{
	impl_.erase( impl_.begin()+index );
}

void ThreadBase::add( const ThreadImplRef& ref)
{
	impl_.push_back(ref);
}



}}}}



sd::tools::thread::Thread::Thread( int uid )
{
	add( ThreadImplRef( new impl::ThreadImpl(uid)));
}


sd::tools::thread::Thread::Thread( const tools::HHANDLE& handle )
{
	add(ThreadImplRef(new impl::ThreadImpl(handle)));
}

sd::tools::thread::Thread::Thread()
{
	add(ThreadImplRef( impl::createThisThread()));
}


int sd::tools::thread::Thread::getId()const
{
	assert( size()==1 );
	return get(0)->getId();	
}



void Thread::join()
{
	assert( size()==1 );
	get(0)->join();	
}


const void* Thread::getCurrentEIP()const
{
	assert( size()==1 );
	return get(0)->getCurrentEIP();	
}


bool Thread::timed_join(int msec_time)
{
	assert( size()==1 );	
	return get(0)->timed_join(msec_time);
}


void ThreadGroup::CreateThread( int uid )
{
	add(ThreadImplRef(new impl::ThreadImpl(uid)));
}
void ThreadGroup::CreateThread( const sd::tools::HHANDLE& handle )
{
	add(ThreadImplRef(new impl::ThreadImpl(handle)));
}

void ThreadGroup::addThread(const Thread& thread)
{
	const ThreadBase& base = thread;
	assert( base.size()==1 );	
	add( base.get(0) );
}
void ThreadGroup::removeThread(const Thread& thread)
{
	assert( thread.size()==1 );	
	int index = find(thread.get(0));
	assert(index!=-1);
	remove(index);
}
void ThreadGroup::addGroup(const ThreadGroup& group)
{
	const ThreadBase& base = group;
	for(size_t i=0; i<group.size(); ++i)
		add( base.get(0) );
}
void ThreadGroup::removeGroup(const ThreadGroup& group)
{
	const ThreadBase& base = group;
	for(size_t i=0; i<group.size(); ++i)
	{
		int index = find(base.get(i));
		assert(index!=-1);
		remove(index);
	}
}

Thread ThreadGroup::get(int index)
{
	assert( index>=0 && index < (int)size());
	return Thread( ThreadBase::get(index) );
}


Thread ThreadGroup::get(int index)const
{
	assert( index>=0 && index < (int)size());
	return Thread( ThreadBase::get(index) );
}

int ThreadGroup::find( const Thread& thread )
{
	for(size_t i=0; i < size(); ++i)
		if( get(i).getId() == thread.getId() )
			return i;
	return -1;
}


void ThreadGroup::join( bool wait_all )
{
	impl::multi_join( begin(), end(), wait_all, 0 );
}
bool ThreadGroup::timed_join(int msec_time, bool wait_all  )
{
	return impl::multi_join( begin(), end(), wait_all, msec_time );
}


